//package com.example.mydemo.util;
//
//import com.example.mydemo.entity.Clock;
//
//import com.example.mydemo.mapper.ClockMapper;
//
//import com.example.mydemo.service.IClockService;
//import com.zaxxer.hikari.HikariConfig;
//import com.zaxxer.hikari.HikariDataSource;
//import lombok.Data;
//import org.apache.ibatis.session.SqlSession;
//import org.apache.ibatis.session.SqlSessionFactory;
//import org.mybatis.spring.SqlSessionFactoryBean;
//import org.mybatis.spring.annotation.MapperScan;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.AnnotationConfigApplicationContext;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
//import org.springframework.jdbc.datasource.DataSourceTransactionManager;
//import org.springframework.transaction.PlatformTransactionManager;
//
//import javax.sql.DataSource;
//import java.sql.SQLException;
//import java.time.Duration;
//import java.time.LocalDate;
//import java.time.LocalDateTime;
//import java.time.LocalTime;
//import java.time.format.DateTimeFormatter;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Random;
//import java.util.concurrent.*;
//import java.util.concurrent.atomic.AtomicInteger;
//
//// 直接执行的主类
//public class ClockDataGenerator {
//
//    @Autowired
//    private IClockService clockService;
//    // 线程池配置
//    private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
//    private static final ExecutorService FIXED_THREAD_POOL = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
//    private static final AtomicInteger TOTAL_INSERTED = new AtomicInteger(0);
//    private static final Random RANDOM = new Random();
//
//    // 数据库配置（根据实际情况修改）
//    private static final String DB_URL = "jdbc:mysql://localhost:3306/my_spring_boot_db?useSSL=false&serverTimezone=Asia/Shanghai";
//    private static final String DB_USER = "root";
//    private static final String DB_PASSWORD = "root";
//    private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
//
//    // 主方法：直接执行
//    public static void main(String[] args) {
//        try {
//            // 1. 初始化数据库连接和 MyBatis
//            DataSource dataSource = initDataSource();
//            SqlSessionFactory sqlSessionFactory = initSqlSessionFactory(dataSource);
//            ClockMapper clockMapper = sqlSessionFactory.openSession().getMapper(ClockMapper.class);
//            ClockService clockService = new ClockServiceImpl(clockMapper);
//
//            // 2. 生成并插入数据
//            DirectClockDataGenerator generator = new DirectClockDataGenerator(clockService);
//            generator.generateAndInsert();
//
//        } catch (Exception e) {
//            System.err.println("程序运行失败: " + e.getMessage());
//            e.printStackTrace();
//        }
//    }
//
//    /**
//     * 初始化数据源
//     */
//    private static DataSource initDataSource() throws SQLException {
//        // 使用 HikariCP 连接池（需添加依赖）
//        HikariConfig config = new HikariConfig();
//        config.setJdbcUrl(DB_URL);
//        config.setUsername(DB_USER);
//        config.setPassword(DB_PASSWORD);
//        config.setDriverClassName(DRIVER_CLASS);
//        config.setMaximumPoolSize(THREAD_POOL_SIZE); // 连接池最大连接数=线程数
//        config.setMinimumIdle(4);
//        config.setConnectionTimeout(30000);
//        return new HikariDataSource(config);
//    }
//
//    /**
//     * 初始化 MyBatis SqlSessionFactory
//     */
//    private static SqlSessionFactory initSqlSessionFactory(DataSource dataSource) throws Exception {
//        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//        factoryBean.setDataSource(dataSource);
//        // 指定 Mapper XML 路径（根据实际路径调整）
//        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/**/*.xml"));
//        return factoryBean.getObject();
//    }
//
//    // ====================== 核心逻辑 ======================
////    private final ClockService clockService;
////
////    public DirectClockDataGenerator(ClockService clockService) {
////        this.clockService = clockService;
////    }
//
//    /**
//     * 主流程：生成并插入打卡数据
//     */
//    public void generateAndInsert() {
//        // 1. 查询所有有效员工（示例用模拟数据，实际需查询数据库）
//        List<EmployeeInfo> employees = getEmployeeInfos();
//        if (employees.isEmpty()) {
//            System.err.println("员工表无数据，无法生成打卡记录！");
//            return;
//        }
//
//        // 2. 拆分员工列表为多个子任务（按线程数拆分）
//        int totalEmployees = employees.size();
//        int batchSizePerThread = (int) Math.ceil((double) totalEmployees / THREAD_POOL_SIZE);
//
//        // 3. 提交子任务到线程池
//        List<Callable<Void>> tasks = new ArrayList<>();
//        for (int i = 0; i < THREAD_POOL_SIZE; i++) {
//            int start = i * batchSizePerThread;
//            int end = Math.min((i + 1) * batchSizePerThread, totalEmployees);
//            List<EmployeeInfo> subEmployees = employees.subList(start, end);
//            tasks.add(() -> processEmployeeBatch(subEmployees));
//        }
//
//        // 4. 等待所有任务完成并统计结果
//        try {
//            List<Future<Void>> futures = FIXED_THREAD_POOL.invokeAll(tasks);
//            for (Future<Void> future : futures) {
//                future.get(); // 检查任务是否异常
//            }
//            System.out.println("成功插入 " + TOTAL_INSERTED.get() + " 条打卡记录！");
//        } catch (InterruptedException | ExecutionException e) {
//            System.err.println("多线程插入失败: " + e.getMessage());
//            e.printStackTrace();
//        } finally {
//            FIXED_THREAD_POOL.shutdown();
//        }
//    }
//
//    /**
//     * 处理一批员工的打卡记录生成与插入（线程任务）
//     */
//    private Void processEmployeeBatch(List<EmployeeInfo> employees) {
//        List<Clock> batchBuffer = new ArrayList<>(1000); // 批量缓冲区（每1000条插入一次）
//
//        for (EmployeeInfo emp : employees) {
//            List<Clock> empClocks = generateEmployeeClocks(emp);
//            for (Clock clock : empClocks) {
//                batchBuffer.add(clock);
//
//                // 缓冲区满时触发批量插入
//                if (batchBuffer.size() >= 1000) {
//                    insertBatch(batchBuffer);
//                    TOTAL_INSERTED.addAndGet(batchBuffer.size());
//                    System.out.println(Thread.currentThread().getName() + " 插入 " + batchBuffer.size() + " 条");
//                    batchBuffer.clear();
//                }
//            }
//        }
//
//        // 插入剩余记录（不足1000条）
//        if (!batchBuffer.isEmpty()) {
//            insertBatch(batchBuffer);
//            TOTAL_INSERTED.addAndGet(batchBuffer.size());
//            System.out.println(Thread.currentThread().getName() + " 插入剩余 " + batchBuffer.size() + " 条");
//        }
//
//        return null;
//    }
//
//    /**
//     * 批量插入打卡记录（调用 Service）
//     */
//    private void insertBatch(List<Clock> buffer) {
//        try {
//            clockService.batchInsertOptimized(buffer);
//        } catch (Exception e) {
//            System.err.println("批量插入失败: " + e.getMessage());
//            e.printStackTrace();
//        }
//    }
//
//    // ====================== 辅助方法 ======================
//    /**
//     * 查询员工表中所有有效员工（示例用模拟数据）
//     */
//    private List<EmployeeInfo> getEmployeeInfos() {
//        // 实际开发中替换为数据库查询（示例数据）
//        List<EmployeeInfo> employees = new ArrayList<>();
//        employees.add(new EmployeeInfo(1L, LocalDate.of(2024, 1, 1)));
//        employees.add(new EmployeeInfo(2L, LocalDate.of(2024, 2, 15)));
//        return employees;
//    }
//
//    /**
//     * 生成单个员工的所有打卡记录（从雇佣日期到今天）
//     */
//    private List<Clock> generateEmployeeClocks(EmployeeInfo emp) {
//        List<Clock> records = new ArrayList<>();
//        DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//        Random random = new Random();
//
//        LocalDate currentDate = LocalDate.now();
//        LocalDate startDate = emp.getHireDate();
//
//        if (startDate.isAfter(currentDate)) {
//            System.out.printf("员工 %d 的雇佣日期 %s 晚于今天，跳过%n", emp.getEmployeeId(), startDate);
//            return records;
//        }
//
//        for (LocalDate date = startDate; !date.isAfter(currentDate); date = date.plusDays(1)) {
//            if (date.getDayOfWeek().getValue() >= 6) continue; // 跳过周末
//
//            int clockCount = generateDailyClockCount(random);
//            switch (clockCount) {
//                case 0:
//                    break;
//                case 1:
//                    if (random.nextBoolean()) {
//                        records.add(generateWorkRecord(emp.getEmployeeId(), date, dtFormatter, random));
//                    } else {
//                        records.add(generateOffRecord(emp.getEmployeeId(), date, dtFormatter, random));
//                    }
//                    break;
//                case 2:
//                    records.add(generateWorkRecord(emp.getEmployeeId(), date, dtFormatter, random));
//                    records.add(generateOffRecord(emp.getEmployeeId(), date, dtFormatter, random));
//                    break;
//                default:
//                    throw new IllegalStateException("Unexpected value: " + clockCount);
//            }
//        }
//        return records;
//    }
//
//    /**
//     * 生成单条上班打卡记录
//     */
//    private Clock generateWorkRecord(Long employeeId, LocalDate date, DateTimeFormatter formatter,
//                                     Random random) {
//        // 正常时间范围（8:30-9:00）占80%，迟到（9:00-9:30）占15%，严重迟到（>9:30）占5%
//        double timeProb = random.nextDouble();
//        LocalTime clockTime;
//        if (timeProb < 0.97) {
//            clockTime = LocalTime.of(8, 30).plusMinutes(random.nextInt(31));
//        } else if (timeProb < 0.99) {
//            clockTime = LocalTime.of(9, 0).plusMinutes(random.nextInt(31));
//        } else {
//            clockTime = LocalTime.of(9, 30).plusMinutes(random.nextInt(31));
//        }
//
//        int status;
//        String remark;
//        LocalTime workStart = LocalTime.of(9, 0);
//        Duration lateThreshold = Duration.ofMinutes(30);
//        if (clockTime.isBefore(workStart.plus(lateThreshold))) {
//            status = 1;
//            remark = "正常";
//        } else {
//            status = 2;
//            Duration delay = Duration.between(workStart, clockTime);
//            remark = "迟到" + delay.toMinutes() + "分钟";
//        }
//
//        String location = generateRandomLocation();
//        return buildClockRecord(employeeId, 1, status, formatter.format(date.atTime(clockTime)), location, remark);
//    }
//
//    /**
//     * 生成单条下班打卡记录
//     */
//    private Clock generateOffRecord(Long employeeId, LocalDate date, DateTimeFormatter formatter, Random random) {
//        // 正常时间范围（17:30-18:00）占85%，早退（17:00-17:30）占10%，严重早退（<17:00）占5%
//        double timeProb = random.nextDouble();
//        LocalTime clockTime;
//        if (timeProb < 0.98) {
//            clockTime = LocalTime.of(18, 0).plusMinutes(random.nextInt(31));
//        } else if (timeProb < 0.99) {
//            clockTime = LocalTime.of(17, 30).plusMinutes(random.nextInt(31));
//        } else {
//            clockTime = LocalTime.of(17, 30).minusMinutes(random.nextInt(31));
//        }
//
//        int status;
//        String remark;
//        LocalTime workEnd = LocalTime.of(18, 0);
//        if (clockTime.isAfter(workEnd)) {
//            status = 1;
//            remark = "正常";
//        } else {
//            status = 3;
//            Duration early = Duration.between(clockTime, workEnd);
//            remark = "早退" + early.toMinutes() + "分钟";
//        }
//
//        String location = generateRandomLocation();
//        return buildClockRecord(employeeId, 2, status, formatter.format(date.atTime(clockTime)), location, remark);
//    }
//
//    /**
//     * 生成公司位置附近的随机经纬度
//     */
//    private static String generateRandomLocation() {
//        double[] companyCoords = {116.404, 39.915};
//        double randomLon = companyCoords[0] + (RANDOM.nextDouble() - 0.5) * 0.02;
//        double randomLat = companyCoords[1] + (RANDOM.nextDouble() - 0.5) * 0.02;
//        return String.format("%.6f,%.6f", randomLon, randomLat);
//    }
//
//    /**
//     * 生成当日打卡次数（0/1/2次）
//     */
//    private static int generateDailyClockCount(Random random) {
//        double probability = random.nextDouble();
//        if (probability < 0.01) return 0;
//        else if (probability < 0.02) return 1;
//        else return 2;
//    }
//
//    /**
//     * 构造打卡记录对象
//     */
//    private static Clock buildClockRecord(Long empId, int type, int status,
//                                          String time, String location, String remark) {
//        return new Clock(
//                null, empId, type, status, time, location, remark,
//                0L, "system", LocalDateTime.now(), "system", LocalDateTime.now()
//        );
//    }
//
//    // 员工信息内部类
//    @Data
//    public static class EmployeeInfo {
//        private Long employeeId;
//        private LocalDate hireDate;
//
//        public EmployeeInfo(Long employeeId, LocalDate hireDate) {
//            this.employeeId = employeeId;
//            this.hireDate = hireDate;
//        }
//    }
//}